package com.fulihui.usercore.biz.shard.impl;

import com.fulihui.usercore.biz.shard.WechatUserManager;
import com.fulihui.usercore.common.util.AppProps;
import com.fulihui.usercore.common.util.Errors;
import com.fulihui.usercore.core.repository.UserLoginRepository;
import com.fulihui.usercore.core.repository.WechatOpenidHelpRepository;
import com.fulihui.usercore.core.repository.WechatUnionidHelpRepository;
import com.fulihui.usercore.core.repository.WechatUserRepository;
import com.fulihui.usercore.dal.dataobj.LoginDO;
import com.fulihui.usercore.dto.WechatUserDTO;
import com.fulihui.usercore.enums.WechatOpenIdTypeEnum;
import org.near.servicesupport.error.InvokeServiceException;
import org.near.toolkit.common.EnumUtil;
import org.near.toolkit.common.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

/**
 * @author Willard.Hu on 2016/12/2 0002.
 */
@Component
public class WechatUserManagerImpl implements WechatUserManager {
    @Autowired
    WechatUserRepository wechatUserRepository;
    @Autowired
    UserLoginRepository  userLoginRepository;
    @Autowired
    AppProps             appProps;
    @Autowired
    WechatOpenidHelpRepository wechatOpenidHelpRepository;
    @Autowired
    WechatUnionidHelpRepository wechatUnionidHelpRepository;
    @Autowired
    private TransactionTemplate transactionTemplate;

    /**
     * @see WechatUserManager#checkBindByUserId(String, String, String, String)
     */
    @Override
    public boolean checkBindByUserId(String openId, String openidType, String userId, String appid) {
        Assert.hasLength(openId);
        Assert.hasLength(openidType);
        Assert.hasLength(userId);
        appid = checkOpenidTypeAndGetDefaultAppidIfNil(appid, openidType);

        WechatUserDTO dto = wechatUserRepository.querySingle(openId,
                openidType, appid);
        return dto != null && dto.getUserId().equals(userId);
    }

    /**
     * @see WechatUserManager#checkBindByLoginId(String, String, String, String, String)
     */
    @Override
    public boolean checkBindByLoginId(String loginId, String openId, String openidType, String userId, String appid) {
        LoginDO loginDO = userLoginRepository.queryByPK(loginId);
        Assert.notNull(loginDO, "账号" + loginId + "还未注册");
        return checkBindByUserId(openId, openidType, loginDO.getUserId(), appid);
    }

    /**
     * @see WechatUserManager#bindingByUserId(WechatUserDTO)
     */
    @Override
    public void bindingByUserId(WechatUserDTO record) {
        Assert.hasLength(record.getOpenId());
        Assert.hasLength(record.getOpenidType());
        Assert.hasLength(record.getUserId());
        Assert.hasLength(record.getUnionid());
        record.setAppid(checkOpenidTypeAndGetDefaultAppidIfNil(record.getAppid(), record.getOpenidType()));
        WechatUserDTO dto = wechatOpenidHelpRepository.querySingle(record.getOpenId(), record.getOpenidType(),
                record.getAppid());
        // 微信 appid, openidType, openId 已被绑定
        if (dto != null) {
            // 用户自己绑定的，不用再次绑定
            if (StringUtil.equals(dto.getUserId(), record.getUserId())) {
                return;
            }
            // 被其他人绑定的
            throw new InvokeServiceException(Errors.User.WECHAT_HAS_BINDING_USER);
        }
        /**
         * 事务 保证 同事插入3张表
         */
        transactionTemplate.execute(status -> {
            try {
                wechatUserRepository.create(record);
                wechatOpenidHelpRepository.create(record);
                wechatUnionidHelpRepository.create(record);
            } catch (Exception e) {
                status.setRollbackOnly();
                return false;
            }
            return true;
        });
    }

    /**
     * @see WechatUserManager#bindingByLoginId(String, WechatUserDTO)
     */
    @Override
    public void bindingByLoginId(String loginId, WechatUserDTO record) {
        LoginDO loginDO = userLoginRepository.queryByPK(loginId);
        Assert.notNull(loginDO, "账号" + loginId + "还未注册");
        record.setUserId(loginDO.getUserId());
        bindingByUserId(record);
    }

    /**
     * 检查 openidType 类型是否合法，并且检查appid是否有值，
     * 没有值的话，通过openidType获取默认值
     *
     * @param appid      微信平台标识
     * @param openidType openid类型，APP / MP
     * @return appid有值，直接返回appid，否则通过openidType获取默认的appid
     */
    private String checkOpenidTypeAndGetDefaultAppidIfNil(String appid, String openidType) {
        if (StringUtil.isBlank(appid)) {
            if (WechatOpenIdTypeEnum.WECHAT_MP.getCode().equals(openidType)) {
                appid = appProps.getWechatMpAppid();
            } else if (WechatOpenIdTypeEnum.NATIVE_APP.getCode().equals(openidType)) {
                appid = appProps.getWechatAppAppid();
            } else {
                throw new IllegalArgumentException("非法的openidType:" + openidType);
            }
        } else {
            Assert.isTrue(EnumUtil.inEnum(openidType, WechatOpenIdTypeEnum.class),
                    "非法的openidType:" + openidType);
        }
        return appid;
    }
}
